---
menu: Active Proposals
name: Focusgroup (Explainer)
path: /components/scoped-focusgroup.explainer
layout: ../../layouts/ComponentLayout.astro
---

 - Authors: [Jacques Newman](https://github.com/janewman)
 - Prior Authors from the earlier, broader [focusgroup explainer](/components/focusgroup.explainer): [Travis Leithead](https://github.com/travisleithead), [David Zearing](https://github.com/dzearing), [Chris Holt](https://github.com/chrisdholt)
 - WHATWG issue: https://github.com/whatwg/html/issues/11641
 - Last updated: 2025-10-7

## Table of Contents
<details>
<summary><strong>Show / Hide Table of Contents</strong></summary>

- [Introduction](#introduction)
  - [Keyboard Navigation Modes](#keyboard-navigation-modes)
    - [1. Sequential focus navigation](#1-sequential-focus-navigation)
    - [2. Directional navigation](#2-directional-navigation)
  - [Before / After at a glance](#before--after-at-a-glance)
- [Focusgroup Tokens](#focusgroup-tokens)
- [Differences from the original explainer](#differences-from-the-original-explainer)
  - [CSS support is now a future consideration](#css-support-is-now-a-future-consideration)
  - [Grid support is now a future consideration](#grid-support-is-now-a-future-consideration)
  - [Focusgroup is now scoped to specific scenarios](#focusgroup-is-now-scoped-to-specific-scenarios)
  - [Supported Behaviors](#supported-behaviors)
    - [Behavior → role mapping & precedence](#behavior--role-mapping--precedence)
- [Why not just add new native elements to cover these patterns?](#why-not-just-add-new-native-elements-to-cover-these-patterns)
- [Quickstart](#quickstart)
- [Goal](#goal)
  - [Non-Goals](#non-goals)
- [Principles](#principles)
- [Use Cases](#use-cases)
- [Focusgroup Concepts](#focusgroup-concepts)
  - [Focusgroup segments](#focusgroup-segments)
  - [Last-focused memory](#last-focused-memory)
  - [Guaranteed tab stop](#guaranteed-tab-stop)
  - [Shadow DOM boundaries](#shadow-dom-boundaries)
  - [Key conflicts](#key-conflicts)
  - [Interactive content inside focusgroups](#interactive-content-inside-focusgroups)
  - [Key conflict elements](#key-conflict-elements)
    - [Escape behavior for native key conflict elements](#escape-behavior-for-native-key-conflict-elements)
  - [Scrolling interactions](#scrolling-interactions)
    - [1. Focusgroup within a scrollable region](#1-focusgroup-within-a-scrollable-region)
    - [2. Scrollable region within a focusgroup](#2-scrollable-region-within-a-focusgroup)
  - [Interaction with related web platform features](#interaction-with-related-web-platform-features)
    - [Reading flow](#reading-flow)
    - [ARIA orientation](#aria-orientation)
  - [Restricted elements](#restricted-elements)
  - [Feature detection](#feature-detection)
  - [Additional features](#additional-features)
- [Enabling wrapping behaviors](#enabling-wrapping-behaviors)
- [Limiting linear focusgroup directionality](#limiting-linear-focusgroup-directionality)
- [Opting-out](#opting-out)
  - [Impact on sequential focus navigation](#impact-on-sequential-focus-navigation)
  - [Nested Focusgroups](#nested-focusgroups)
- [Disabling focusgroup memory](#disabling-focusgroup-memory)
- [Adjustments to sequential focus navigation](#adjustments-to-sequential-focus-navigation)
  - [Guaranteed tab stop algorithm](#guaranteed-tab-stop-algorithm)
- [(Future Consideration) Grid focusgroups](#future-consideration-grid-focusgroups)
- [(Future Consideration) Additional Keyboard support](#future-consideration-additional-keyboard-support)
- [Alternatives considered](#alternatives-considered)
- [Open Questions](#open-questions)
- [Privacy and Security Considerations](#privacy-and-security-considerations)
  - [Privacy](#privacy)
  - [Security](#security)
- [Design decisions](#design-decisions)
- [Index of focusgroup values](#index-of-focusgroup-values)
- [Acknowledgments](#acknowledgments)

</details>
## Introduction

Authors routinely hand-code “roving tabindex” logic for composite widgets like toolbars, tablists, menus, listboxes and grids. In practice, this means providing a single tab stop to enter the control, then using directional navigation (arrow keys / D-pad) to move focus between items.

Authors may use the proposed `focusgroup` HTML attribute to declare that
a subtree of focusable elements will get:
1. Focus navigation ([not selection](#non-goals)) using directional navigation (arrow key, D-pads, etc.).
2. A guaranteed tab stop (when at least one focusable element is present) (see [Guaranteed tab stop](#guaranteed-tab-stop)).
3. Automatic return to the last focused focusable element (unless [`no-memory`](#disabling-focusgroup-memory) is set).
4. Optional limited-axis arrow key navigation and optional wrap-around semantics.

By standardizing `focusgroup`, authors can leverage these behaviors in
[control patterns](https://www.w3.org/WAI/ARIA/apg/) to provide users with keyboard consistency,
default accessibility, and interoperability over existing solutions.

While this document emphasizes the usage of the keyboard arrow keys for accessibility
navigation, we acknowledge that there are other input modalities that work (or can be adapted
to work) equally well for `focusgroup` navigation behavior (e.g., game controllers,D-pads, remote controls, gesture
recognizers, touch-based assistive technologies (AT), etc.).

Benefits over ad-hoc scripts (FocusZone, Tabster, bespoke roving tabindex): less boilerplate, standardized axis + wrap behavior (including RTL / vertical), reduced misapplication, and a consistent, testable baseline for AT and UA interoperability.

### Keyboard Navigation Modes
Two complementary navigation paradigms are often used on the web today:

#### 1. Sequential focus navigation
 (Tab / Shift+Tab): The browser-managed order of tabbable elements (`tabindex` / native semantics). Used to enter or leave a composite. This navigation respects the CSS [`reading-flow`](#reading-flow) property when present, following the visual reading order rather than DOM order; if `reading-flow` is not set it follows DOM source order.
#### 2. Directional navigation
 (Arrow keys, D-pad, some AT commands): Moves focus among a logically related set of items inside a composite without leaving it, the “[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)” pattern when hand-authored. Directional movement aligns with the visual order established by [`reading-flow`](#reading-flow) so that an arrow key press moves focus in the expected visual direction.

### Before / After at a glance:

Before (manual roving tabindex JS):
```html
<div role="toolbar" aria-label="Text formatting" id="fmtToolbar">
  <button type="button">Bold</button>
  <button type="button">Italic</button>
  <button type="button">Underline</button>
</div>
<script>
  // Without focusgroup an author script must implement:
  //  - Focus management (roving tabindex: keep exactly one item tabbable, skip disabled/hidden).
  //  - Keyboard navigation (Arrow keys, Home/End, optional wrap, writing mode/RTL handling).
  //  - Memory (restore last focused item on re-entry).
  // Plus any domain logic (selection state, toggles, menus, tooltips, custom commands, etc.).
  // focusgroup makes the first three bullets declarative; authors keep only selection & feature logic.
</script>
```
After (single declarative attribute):
```html
<div focusgroup="toolbar wrap" aria-label="Text formatting">
  <button type="button">Bold</button>
  <button type="button">Italic</button>
  <button type="button">Underline</button>
</div>
<script>
  // Now with focusgroup, the author only needs to implement selection & feature logic.
</script>
```
What changed:
* `focusgroup="toolbar wrap"` supplies the role (first token) + wrap behavior.
* Roving tabindex + arrow key handling + memory are native (no JS for core movement).
* Selection / pressed state (e.g., toggling Bold) and any advanced commands remain author logic.

## Focusgroup Tokens

Simple usage (space-separated tokens):

```html
<div focusgroup="<behavior> [inline|block] [wrap] [no-memory]">
  <button>One</button>
  <button>Two</button>
  <button>Three</button>
</div>
```

Opting an element and its subtree out of an ancestor focusgroup, see: [Opting-out](#opting-out):
```html
<div focusgroup="none"></div>
```

Specifying a specific item as the [entry point](#entry-point) for focus when entering a focusgroup:
```html
<div focusgroup="<behavior> [inline|block] [wrap] [no-memory]">
  <button>One</button>
  <button>Two</button>
  <button>Three</button>
</div>
```

| Token | Required? | What it does |
|-------|-----------|--------------|
| `<behavior>` | Yes (unless using [`none`](#opting-out)) | Token describing the intended behavior. See: [Supported Behaviors](#supported-behaviors). |
| [`inline`](#limiting-linear-focusgroup-directionality) / [`block`](#limiting-linear-focusgroup-directionality) | Optional | Restrict arrow navigation to that logical axis. Omit to allow both axes. |
| [`wrap`](#enabling-wrapping-behaviors) | Optional | Loops end→start and start→end. |
| [`no-memory`](#disabling-focusgroup-memory) | Optional | Disable restoring last-focused item on re-entry (memory is on by default). |
| [`none`](#opting-out) | Standalone | Opt-out: exclude element and its subtree from ancestor focusgroup. Cannot be combined with any other token. |

## Major Differences from the original explainer
[Original focusgroup explainer.](/components/focusgroup.explainer)
### CSS support is now a future consideration
Applying `focusgroup` (and related behaviors) via CSS is out of scope for this explainer and deferred for a possible, backwards-compatible future addition.

### Grid support is now a future consideration
Applying `focusgroup` to grid-like structures (2-D navigation) is out of scope for this explainer and deferred for a possible, backwards-compatible future addition.

### Focusgroup is now scoped to specific scenarios
Earlier drafts explored applying `focusgroup` to any container. Broad, role-agnostic usage risks normalizing arrow navigation in semantically neutral wrappers ("div soup"), masking missing semantics and creating unexpected keyboard loops. The proposal now:

* Limits activation to a concise, enumerated set of behavior tokens associated with recognized widget patterns.
* Allows (when omitted) safe [child role inference](#open-questions) for common item types to reduce boilerplate and steer toward APG-aligned structures.
* Keeps ARIA roles semantic-only: the `focusgroup` attribute supplies behavior intent; an explicit `role` attribute remains optional unless the author needs a different role than the first token.

Benefits of this scoped, behavior-first approach:
* Guardrails: Prevents accidental application to arbitrary layout groupings without a recognized composite role.
* Ergonomics: One attribute encodes both composite intent and navigation modifiers (`wrap`, `inline`, etc.).
* Extensibility: Additional composite roles (or a role-agnostic mode) can be considered later based on demonstrated accessible patterns; narrowing later would be impractical.

Open aspects still under discussion appear in the Open Questions (e.g., set of supported behaviors, child role inference).

### Supported Behaviors
The first token in a `focusgroup` attribute is a behavior token. A behavior token declares an interaction pattern (e.g., toolbar behavior). User agents MUST expose a corresponding minimum ARIA role for accessibility if the author does not supply an explicit, compatible role or if the author doesn't use a native element with a recognized role. This separates interaction (behavior) from semantics (role mapping) while keeping authoring terse.
Minimum role application (container & children): User agents apply the minimum container role for a behavior only when (a) the author has not provided an explicit `role` AND (b) the element would otherwise expose a generic role (e.g., a plain `<div>`/`<span>`). If the host already has non-generic native semantics (e.g., `<ul>`, `<nav>`, `<table>`) or an explicit role, the mapping is skipped; navigation behavior still applies. Child role inference likewise only occurs when: (1) the container role was supplied via the behavior's minimum role mapping (not explicit/native), (2) the child lacks an explicit role, and (3) the child itself is otherwise generic or less specific than the inferred role. Native interactive elements (buttons, links, inputs, etc.) or anything with an explicit/non-generic role are never overwritten.

Current behavior tokens (APG alignment & minimum roles). All listed (except the future grid token) produce the same linear navigation semantics—only semantic expectations & child inference differ:

| Behavior | APG Pattern | Minimum container role (when applied) | Minimum child role(s) (when applied) | APG Pattern Link |
|---|---|---|---|---|
| `toolbar` | Toolbar | [`toolbar`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/toolbar_role) | (none) | [APG Toolbar](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/) |
| `tablist` | Tabs | [`tablist`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role) | [`tab`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role) | [APG Tabs](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) |
| `radiogroup` | Radio Group | [`radiogroup`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/radiogroup_role) | [`radio`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/radio_role) | [APG Radio Group](https://www.w3.org/WAI/ARIA/apg/patterns/radio/) |
| `listbox` | Listbox | [`listbox`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role) | [`option`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/option_role) | [APG Listbox](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/) |
| `menu` | Menu | [`menu`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menu_role) | [`menuitem`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menuitem_role) | [APG Menu / Menubar](https://www.w3.org/WAI/ARIA/apg/patterns/menu/) |
| `menubar` | Menubar | [`menubar`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menubar_role) | [`menuitem`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menuitem_role) | [APG Menu / Menubar](https://www.w3.org/WAI/ARIA/apg/patterns/menu/) |
| `grid` (future) | Grid (2-D) | [`grid`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/grid_role) | (TBD) | [APG Grid](https://www.w3.org/WAI/ARIA/apg/patterns/grid/) |

#### Behavior → role mapping & precedence
2. No explicit container `role`: UA maps behavior token to its minimum role (subject to minimum-role conditions described above).
3. Explicit container `role` identical to minimum role: keep as-is.
4. Explicit compatible composite `role`: keep explicit role; behavior navigation still activates.
5. Explicit incompatible `role` (e.g., `button`): UA MAY activate a developer warning.
6. Child role inference only runs when: (a) container role came from behavior mapping, (b) descendant is managed (not opted-out), (c) behavior defines an inferred child role, (d) descendant lacks explicit `role`, (e) inference would not replace richer native semantics. This endures an inferred, minimum role will never override an explicit role.
7. Inference never upgrades variant types (e.g., `menuitemcheckbox` vs `menuitemradio`)—authors must specify those explicitly.

This approach separates behavioral intent (token) from accessibility semantics (minimum role mapping) and addresses concerns about reusing ARIA role strings directly as activation tokens.

## Why not just add new native elements to cover these patterns?
There are already proposals to add native versions of several of the patterns
focusgroup would help with, rather than introduce this new attribute, why shouldn't we
instead focus on building these patterns directly into HTML?

Reasons to pursue `focusgroup` in parallel:
1. Author choice (custom elements / design systems): Many teams intentionally wrap primitives in web components or framework components and may not adopt new native container elements even if available. `focusgroup` lets them keep existing markup patterns while still standardizing navigation and reducing JS.
2. Incremental flexibility: Adding a new eligible behavior token (and optional child inference) is a far smaller spec and implementation change than introducing a new HTML element with parsing, styling, accessibility mapping, and legacy considerations.
3. Low friction upgrade path: Existing ARIA patterns (toolbar of buttons, listbox of options) become declarative with a single attribute rather than refactoring to new tags.
4. Progressive expansion: We can start with a minimal, consensus set (toolbar, tablist, radiogroup, listbox, menu/menubar) and add more patterns as needed.
6. Minimal surface risk: An attribute opt-in is easier to ship, iterate, or adjust (including potential deprecation of an unused token) than an element baked into the content model.
7. Immediate boilerplate win: Solves today's repetitive roving tabindex logic without waiting for multiple element proposals to mature and achieve cross-browser implementation.

`focusgroup` doesn't replace, but complements native elements. It standardizes a widely re-implemented behavioral layer and leaves room for richer, purpose-built elements to integrate or rely on it later.

## Quickstart

The following examples start with the most common composite: a formatting toolbar.

In this example, the author is using a
[tab control pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) where the tab activation
behavior is decoupled from selection ("manual tab activation"):

```html
<div focusgroup="tablist inline wrap no-memory" aria-label="Common Operating Systems">
  <button id="tab-1" aria-selected="false" aria-controls="tabpanel-1">macOS</button>
  <button id="tab-2" aria-selected="true" aria-controls="tabpanel-2" focusgroup-entry-priority>Windows</button>
  <button id="tab-3" aria-selected="false" aria-controls="tabpanel-3">Linux</button>
</div>
<div id="tabpanel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1" hidden> … </div>
<div id="tabpanel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2"> … </div>
<div id="tabpanel-3" role="tabpanel" tabindex="0" aria-labelledby="tab-3" hidden> … </div>
```

What to notice:
* The `focusgroup-entry-priority` attribute on the selected tab determines which tab receives focus when entering the focusgroup.
   The `no-memory` value [prevents the focusgroup from remembering the last focused tab](#disabling-focusgroup-memory) so
   that focus will always go to the tab with `focusgroup-entry-priority` on re-entry regardless of which element was
   focused last.
* If focus is moved via left arrow key to `tab-1`, then pressing the tab key moves focus to
   `tabpanel-2` which is next in sequential focus navigation order (because the other
   `role=tabpanel`s are `hidden`).
* focus will [`wrap`](#enabling-wrapping-behaviors) from one end of the tablist to the other because of `focusgroup=wrap` attribute
   value.
*   the up and down arrow keys **will not** move the focus because of [`focusgroup="inline"`](#limiting-linear-focusgroup-directionality) which
   restricts the axis of movement to keyboard directional arrow keys in the `role="tablist"`'s
   **inline** direction (assuming the `<div>`'s `writing-mode` is `horizontal-tb`).
*   The author code required to manage the selection of a tab is omitted for brevity. Such code on tab selection
   change would update `aria-selected` values, the `hidden` state of the controlled `role="tabpanel"`
   and move the `focusgroup-entry-priority` attribute to the newly selected tab.

In a third example, the author is creating a
[navigation menubar](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/menubar-navigation/).
Both `menuitem`s in the `menubar` ("About" and "Admissions") have popover `menu`s. The "Admissions"
menu has an additional submenu under "Tuition".

```html
<ul focusgroup="menubar inline wrap" aria-label="Mythical University">
  <li role="none">
    <a role="menuitem" popovertarget="aboutpop" href="…">About</a>
    <ul focusgroup="menu block wrap" autofocus id="aboutpop" aria-label="About" popover>
      <li role="none"><a role="menuitem" href="…">Overview</a></li>
      <li role="none"><a role="menuitem" href="…">Administration</a></li>
    </ul>
  </li>
  <li role="none">
    <a role="menuitem" popovertarget="admitpop" href="…">Admissions</a>
    <ul focusgroup="menu block wrap" autofocus id="admitpop" aria-label="Admissions" popover>
      <li role="none"><a role="menuitem" href="…">Apply</a></li>
      <li role="none">
        <a role="menuitem" popovertarget="tuitpop" href="…">Tuition</a>
        <ul focusgroup="menu block wrap" autofocus id="tuitpop" aria-label="Tuition" popover>
          <li role="none"><a role="menuitem" href="…">Undergraduate</a></li>
          <li role="none"><a role="menuitem" href="…">Graduate</a></li>
        </ul>
      </li>
      <li role="none"><a role="menuitem" href="…">Visit</a></li>
    </ul>
  </li>
</ul>
```

What to notice:
- `focusgroup` declarations can be nested inside of other focusgroups. When a nested focusgroup
   is declared on an element, it creates a new focusgroup and [opts-out](#opting-out) of its
   ancestor focusgroup.
- menuitems in `role=menubar` are limited to inline-direction arrow keys (e.g., left and right),
   while menuitems in `role=menu` are limited to block-direction arrow keys (e.g., up and down).
   This allows the orthogonal arrow keys (e.g., up and down on the menubar, left and right on the
   menus) to be used for activation purposes (extra code that is not shown in the example).
- Placement of focus on the menus (the nested focusgroups) from the menubar is not a feature of
   `focusgroup` (nested focusgroups are completely independent of their ancestor focusgroup). In this
   case, the focus placement is handled by built-in `popover` and `autofocus` attribute behaviors.
- the "memory" of the nested `focusgroup`s is reset when the content is hidden/shown--this allows
   the `autofocus` attribute to pick the first focusable element each time a menu is shown--the
   desired behavior in this case.


Opt-out subtree (explicit example):

```html
<div focusgroup="toolbar inline wrap">
  <button>A</button>
  <span focusgroup="none">
    <button>(Not arrow reachable)</button>
  </span>
  <button>B</button>
</div>
```
Items inside the `focusgroup="none"` span are skipped by arrow navigation.

What to notice:
* The opt-out subtree removes its focusable descendants from arrow traversal (ancestor toolbar is eligible) but they remain reachable via Tab.
* Arrow navigation treats the subtree as a single gap—focus jumps from the item before to the item after.
* Useful for excluding infrequent/disruptive controls (e.g., help buttons) from high-frequency arrow flows.

Empirical misuse in uncontrolled contexts; correct usage clusters around APG-backed widget roles. Scoping lowers ambiguity and accelerates interoperable implementation.

Interactions with explicit `role` vs behavior token mapping; also see [open question around child role inference](#open-questions)
```html
<nav id="one" focusgroup="menu inline wrap" aria-label="Formatting">
  <button focusgroup-entry-priority>Bold</button>
  <button role="menuitemcheckbox" aria-checked="true">Italics</button>
  <button>Underline</button>
</nav>
<div id="two" role="toolbar" focusgroup="radiogroup wrap">
  <button type="button" focusgroup-entry-priority>Bold</button>
  <button type="button">Italic</button>
  <button type="button">Underline</button>
</div>
```
What to notice:
* In `#one`, descendants without explicit roles (Bold, Underline) are inferred as `menuitem`; the explicit `menuitemcheckbox` (Italics) is unchanged.
* Inference skips ambiguity: it does not guess a variant (`menuitemradio` vs `menuitemcheckbox`).
* In `#two`, the explicit container `role="toolbar"` overrides the first token `radiogroup`; no radio inference occurs (tokens only supply navigation behavior).
* Arrow key navigation, wrap, and memory behaviors apply in both `#one` and `#two` regardless of whether roles were inferred.
* Authors can obtain behavior without pattern role inference by supplying an explicit conflicting container role when needed.
## Goal

The goal of this feature is to "pave the cow path" of an existing authoring practice
(and accessibility best practice) implemented in nearly every Web UI library: the
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
[[react](https://www.npmjs.com/package/react-roving-tabindex),
[angular](https://material.angular.io/cdk/a11y/overview#listkeymanager),
[fluent](https://developer.microsoft.com/en-us/fluentui#/controls/web/focuszone),
[elix](https://component.kitchen/elix/KeyboardDirectionMixin)]].
Note however, that certain design choices have been made to generalize the
behavior so that additional scenarios are possible. See
[comparing roving tabindex and focusgroup](https://docs.google.com/document/d/1cOxjjZdvFfpexiN1x-MpNJLXrmbrR0xp1sRCTbaQ29c/)
for further details.

To achieve this goal, we believe the solution must be available in declarative markup.
If JavaScript is required, then there seems little advantage to using a built-in feature over
what can be implemented completely in author code. Furthermore, a declarative solution provides
the key signal that allows the platform's accessibility infrastructure to make the `focusgroup`
accessible by default by:

* providing a consistent and reliable navigation usage pattern for users with no extra author code required.
* requiring no new screen reader features: the behaviors (roving tabindex, arrow + Home/End movement,
  optional wrap, last-focused memory) already function today when authored via JavaScript, `focusgroup`
  standardizes intent without introducing novel interaction semantics.
  * Because `focusgroup` requires authors to specify a pattern, and the aria-role of the element and
  controlled descendants are set appropriately, there should be no need for user agents to signal the
  AT to switch to a ["Focus mode"](https://www.accessibility-developer-guide.com/knowledge/screen-readers/desktop/browse-focus-modes/) by default (the user has entered a control group).

### Non-Goals

**Selection Management**
In some [control patterns](https://www.w3.org/WAI/ARIA/apg/) (such as radio groups or tablists)
moving the focus to an element also toggles its **selection** state. While some use cases will
require the selection state to follow the focus, in others these need to be decoupled. `focusgroup`
is decoupled from selection. Tracking and changing selection based on focus will require author
code. Note that a related proposal for tracking selection state,
[**CSS Toggles**](https://tabatkins.github.io/css-toggle/), is
[no longer being pursued](https://docs.google.com/document/d/10JxXgeDAJ5zerOdxoWM9ZU9d5iMOdzGJt0EhlhkOkxM/).

**Visual Indicators**
Implementations are welcome to experiment with additional UI (e.g., a "focusgroup focus ring") in
order to help make users aware of focusgroups, however this proposal does not include any
specific guidelines or recommendations.

**Generic Container Navigation**
This explainer proposes that `focusgroup` should be limited to a specific set of roles to ensure we don't encourage confusing or inaccessible behavior.

## Principles

1. Intuitive use in declarative scenarios. Focusgroups
   - are easy to reason about (self-documenting) in the source markup.
   - provide a rational behavior when nested.
   - integrate well with other related platform semantics (e.g., `tabindex`).
2. Focusgroups are easy to maintain and configure.
   - Configuration is managed in one place.
   - Provide easy to understand usage into HTML patterns.
   - Avoid "spidery connections" e.g., using IDRefs or custom names that are hard to maintain.
3. Complimentary declarative representations in HTML
   - HTML attributes offers focusgroup usage directly with impacted content and provide for
     the most straightforward scenarios.

## Use Cases

1. (Element and subtree opt-in) A focusable element with a supported role and its entire subtree can participate in a single `focusgroup`.
2. (Cross Shadow DOM) Focusable elements contained inside a Shadow DOM are discoverable and focusable when their Shadow Host or an ancestor element declares a `focusgroup`.
3. (Wrap) A `focusgroup` can be configured to have wrap-around focus semantics.
4. (Limit directional arrow keys) A `focusgroup` can be configured to respond to either the logical
   [inline-axis](https://drafts.csswg.org/css-writing-modes-4/#inline-axis) navigation keys (e.g.,
   left and right arrow keys when the `focusgroup` is in a `horizontal-tb`
   [writing mode](https://drafts.csswg.org/css-writing-modes/#block-flow)) or
   [block-axis](https://drafts.csswg.org/css-writing-modes-4/#block-axis) navigation keys or both
   (to trivially reserve one axis of arrow key behavior for supplementary actions, such as opening
   nodes in a tree view control). See
   [CSS Logical Properties and Values](https://drafts.csswg.org/css-logical/) for more about logical
   directions.
5. (Focus movement arrow keys follow content direction) The user's arrow key presses move the focus forward or backward in the DOM according to the writing mode and directionality of the content.  E.g., in RTL, an Arrow-Left key moves the focus forward according to the content direction.
6. (Opt-out) Individual elements can opt-out of `focusgroup` participation.
7. (Grid) A `focusgroup` can be used for grid-type navigation (`<table>`-structured content or other grid-like structured content).

A use case we are evaluating:
* (Grid) A `focusgroup` can be used on elements with `display: grid` to provide 2d grid navigation.

## Focusgroup Concepts

A `focusgroup` is a group of related elements that can be navigated by directional arrow keys and
home/end keys and for which the web platform provides the navigation behavior by default. No
JavaScript event handlers needed in many cases! The behavior of arrow keys depends on the content's writing mode. Keys pointing toward the `block-end` or `inline-end` navigate forward, while keys pointing toward `block-start` or `inline-start` navigate backward.

There are two kinds of `focusgroup`s: **linear `focusgroup`s** and **grid `focusgroup`s**.
Linear `focusgroup`s provide arrow key navigation among a _list_ of elements. Grid `focusgroup`s provide
arrow key navigation behavior for tabular (or 2-dimensional) data structures.

* `focusgroup` or `focusgroup="<behavior>"` (where `<behavior>` is one of the non-grid behaviors) defines a linear `focusgroup`.
* `focusgroup="grid"` defines a grid `focusgroup` (2-D navigation).

Focusgroups consist of a **focusgroup definition** that establishes **focusgroup candidates** and
**focusgroup items**. Focusgroup definitions manage the desired behavior for the associated
focusgroup items. Focusgroup items are the elements that actually participate in the focusgroup
(from the set of focusgroup candidates). Focusgroup candidates are all the elements under the scope
of a focusgroup definition. The **focusgroup scope** consists of the element with the focusgroup
definition and its shadow-inclusive descendants, excluding elements that have opted out.

The minimal focusgroup below demonstrates that the element declaring a focusgroup is also a
focusgroup candidate and (in this case) the single focusgroup item.

```html
<div focusgroup="toolbar">
  <button type="button">Only control</button>
</div>
```

Focusgroup candidates become focusgroup items if they are focusable and do not have a negative `tabindex` value, e.g., implicitly focusable
elements like `<button>` or explicitly made focusable via non-negative `tabindex` values (e.g., a custom element or
`contenteditable`). Elements with `tabindex="-1"` are excluded from focusgroup management entirely.

An element can only have _one_ **focusgroup definition** added via the `focusgroup` attribute:

Example (toolbar with multiple items and one roving tab stop):

```html
<div id="ancestor" focusgroup="toolbar">
  <button id="one" type="button">Bold</button>
  <button id="two" type="button">Italic</button>
  <button id="three" type="button">Underline</button>
  <button id="four" type="button" tabindex="-1">Help</button>
</div>
```

The `ancestor` element has the **focusgroup definition**. The elements with `id=one`, `two`, and
`three` (and any other shadow-inclusive descendants of `ancestor` that may be added) are
**focusgroup candidates**. Because candidates one through three are keyboard focusable, they are considered
**focusgroup items**. When one of the focusgroup items becomes focused, the user can move focus
sequentially among all the focusgroup items using the arrow keys (up/right moves focus forward,
down/left moves focus backwards assuming the `<p>` element has `writing-mode` `horizontal-tb` and
`direction` `ltr`).

Note that only the elements with `id=one`, `id=two` and `id=three` can be focused via arrow keys. The element with `id=four` has `tabindex="-1"`, which takes it out of both [sequential(tab/shift+tab)](##1-sequential-focus-navigation) and [directional(arrow keys)](#2-Directional-navigation) navigation via focusgroup.

### Focusgroup segments

A **focusgroup segment** is a contiguous group of focusgroup items that can be navigated without crossing any [opted-out elements](#opting-out) that are participating in sequential focus navigation. An opted-out element is considered as participating in sequential focus navigation if:
1. The element is opting out of a focusgroup via `focusgroup="none"` or is a descendant of such an element.
2. The element is focusable, i.e., it is either natively focusable or has a non-negative `tabindex`.
3. If the element has a negative tabindex, but currently has focus.

When one of these opted-out elements is between two focusgroup items, it divides the focusgroup into two segments, one segment on each side of the opted-out element.

Each segment operates independently for certain behaviors:
- **Guaranteed tab stop:** Each segment ensures exactly one tab-accessible element.
- **Sequential navigation:** Tab and Shift+Tab treat each segment as a separate focusgroup entry point

For example, if a focusgroup contains items A, B, C, D, E and item C opts-out and would participate in sequential focus navigation, the focusgroup would be split into two segments: [A, B] and [D, E]. Arrow key navigation can move freely across segments, skipping over the opted-out element C, but sequential focus navigation (Tab/Shift+Tab) will treat these as two separate tab stops.

See [Impact on sequential focus navigation](#impact-on-sequential-focus-navigation) for detailed behavior and examples.

### Last-focused memory

By default, focusgroups will remember the last-focused element, and for sequential focus navigation,
will restore focus to that element when a focusgroup is re-entered, if it is present in the focusgroup segment being entered.
This is important for large lists or tables so that users are returned the context they previously left without having to navigate from the start or end sequentially.

The focusgroup's memory is initially empty. In that state, sequential focus navigation will pick
the next element to focus using existing platform behavior
[with the exception noted below](#guaranteed-tab-stop).

The `focusgroup`'s memory is cleared if the last-focused item becomes non-focusable or if its relationship to the `focusgroup` container changes (e.g., it is removed from the DOM). See
[additional details below](#disabling-focusgroup-memory).

### Guaranteed tab stop

Focusgroups provide a special behavior when used in conjunction with sequential focus navigation
("tab navigation"). Focusgroups ensure that **exactly one** focusgroup item will participate in
sequential focus navigation per [segment](#focusgroup-segments), unless there are no focusable items.
This behavior ensures that a `focusgroup` can always be entered via sequential focus navigation.
[See below for further details](#adjustments-to-sequential-focus-navigation).

Focusgroups can therefore be used to provide a
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
among a set of related focusable controls such as this toolbar:

Example:

```html
<div focusgroup="toolbar" aria-label="Text Formatting" aria-controls="…">
  <div>
    <button type="button" aria-pressed="false" value="bold"><span>Bold</span></button>
    <button type="button" aria-pressed="false" value="italic"><span>Italic</span></button>
    <button type="button" aria-pressed="false" value="underline"><span>Underline</span></button>
  </div>
</div>
```

When pressing tab to enter this "toolbar" focusgroup from an element _before_ it, focus will go to
the first `<button>` because:
- There is no other element within the focusgroup with a `tabindex` >= 0 or that is sequentially
   focusable by default (these `<button>`s are taken out of sequential focus navigation with
   `tabindex=-1`).
- This focusgroup has no "memory" of a last-focused element within (e.g., it has not been entered
   before).
- Since neither of the above cases resulted in focusing an alternate element, then the first
   focusgroup item in the group is focused (in DOM order, or if the items are also being managed by reading-flow, in reading order).

At this point, the user can use the arrow keys to move from the beginning of the toolbar to the end,
or press tab again to move outside of the focusgroup.

Note that even if multiple descendants are naturally tabbable (e.g., several `<button>`s without `tabindex`),
`focusgroup` still collapses the group to a single sequential entry point per segment.
Authors do NOT need to manually set `tabindex="-1"` on every non-active item to gain roving behavior.

Example:

```html
<div focusgroup="toolbar" aria-label="Text Formatting" aria-controls="…">
  <div>
    <button type="button" aria-pressed="false" value="bold"><span>Bold</span></button>
    <button type="button" aria-pressed="false" value="italic"><span>Italic</span></button>
    <button type="button" aria-pressed="false" value="underline"><span>Underline</span></button>
  </div>
</div>
```

### Shadow DOM boundaries

Focusgroup definitions apply across Shadow DOM boundaries in order to make it easy for component
developers to support focusgroup behavior across component boundaries. (Component authors that want
to [opt-out of this behavior](#opting-out) can do so.)

Example:

```html
<list-component focusgroup="listbox" role="listbox" aria-label="Cute dogs">
  <template shadowrootmode="open">
    <my-listitem role="option" focusgroup-entry-priority aria-selected="true">Terrier</my-listitem>
    <my-listitem role="option" aria-selected="false">Dalmatian</my-listitem>
    <my-listitem role="option" aria-selected="false">Saint Bernard</my-listitem>
  </template>
</list-component>
```

### Key conflicts
The focusgroup is a default handler for certain keystrokes (keydown events for arrow keys, home/end,
etc.) that will cause focus to move among focusgroup items. This default keyboard handling could
interfere with other actions the application would like to take. A common pattern is to
[limit focusgroup directionality](#limiting-linear-focusgroup-directionality) so that certain
cross-axis keystrokes won't trigger focusgroup behavior. However, if this doesn't address the use
case, then authors may cancel the focusgroup's default behavior at any time by canceling
(`preventDefault()`) the specific keydown event. Keydown events are dispatched by the currently
focused element, and bubble through the focusgroup ancestor element in most cases.

### Interactive content inside focusgroups

Some built-in controls like `<input type=text>` provide keyboard behaviors that "trap" nearly all
keys that would be handled by the focusgroup. Others such as `<input type=number>` trap only certain
keys like the arrow keys that are also used for focusgroup navigation. This proposal **does not**
provide a built-in workaround to prevent this from happening. Instead, authors are advised to be
sure users can "escape" these elements. Built-in elements provide this via the tab key. Other
strategies might include requiring an "activation" step before putting focus into the interactive
control (and an Esc key exit to leave).

#### Key conflict elements

When there is a conflict between the arrow keys consumed by the interactive element and the focusgroup's navigation, focusgroup will **not** interfere with the interactive element's behavior. This means that the normal way to move focus between focusgroup items (arrow keys) will **not** work when focus is within such an element.

Examples:
- `<input>` elements (most, but not all types use arrow keys)
- `<textarea>` elements
- `<select>` elements when the arrow-key axis used by the focusgroup is the same axis used by the select
- Elements with `contenteditable`
- Focusable scrollable regions, when the scroll direction is in the same axis as the focusgroup
- Custom elements with arrow key handlers
- Elements with `preventDefault()` on arrow keys
- Audio and video elements with visible controls
- Iframes and object tags with focusable elements inside

For native elements that conflict, the user agent will provide an [escape behavior](#escape-behavior-for-native-key-conflict-elements).

For authors that add scripted key handlers that consume arrow keys, they should consider the following:
- Implementing an escape behavior similar to the [one provided for native key conflict elements](#escape-behavior-for-native-key-conflict-elements)
- Avoiding conflicts by limiting the focusgroup's axis of movement via [limiting linear focusgroup directionality](#limiting-linear-focusgroup-directionality)
- Using `focusgroup="none"` to opt-out of focusgroup behavior entirely for conflicting elements
- Implementing an "activation" step to enter the custom element (and an "escape" step to leave it)

#### Escape behavior for native key conflict elements

When there is a conflict between the arrow keys consumed by the interactive element and the focusgroup's navigation, focusgroup will **not** interfere with the interactive element's behavior. Instead, focusgroup will provide a way to "escape" the interactive element via the tab key (and Shift+Tab). This means that when focus is within such an element, pressing Tab will move focus to the next focusable element in the focusgroup (if any), and Shift+Tab will move focus to the previous focusable element in the focusgroup (if any).

**Important:** These special behaviors only apply when there is an actual conflict between the arrow keys consumed by the interactive element and the focusgroup's navigation. For example, a focusable scroll container that only uses up/down arrows for scrolling in a focusgroup with `inline` restriction (left/right arrows only) would not be considered a key conflict element for up/down arrow keys, since those keys don't conflict with the focusgroup's navigation.

There are two categories with different behaviors:

**1. Native key conflict elements**

For elements with built-in arrow key behaviors, user agents automatically provide tab-escape functionality. When focus is within such elements, the immediate neighboring focusgroup items become available in the normal tab order. Since focus is already within the focusgroup, memory is **not** taken into consideration, though the author has control over which element is focused next via `tabindex` ordering, using the same considerations as [sequential focus navigation](#adjustments-to-sequential-focus-navigation).

```html
<div focusgroup="toolbar">
  <button>Bold</button>
  <button>Italic</button>
  <div>
    <input type="text" placeholder="Search" /> <!-- Native key conflict -->
    <button>Go</button>
  </div>
  <button>Save</button>
  <button>Print</button>
</div>
```
In this example:
- The input field **is** a focusgroup item reachable via arrow keys.
- Arrow keys are consumed for text cursor navigation once focus is within the input.
- To ensure the user can still reach the other elements in the focusgroup, pressing Tab moves focus to the "Save" button, and Shift+Tab moves focus to the "Italic" button.

```html
<div focusgroup="toolbar">
  <button>Bold</button>
  <button>Italic</button>
  <div>
    <input type="text" placeholder="Search" /> <!-- Native key conflict -->
    <button>Go</button>
  </div>
  <button>Save</button>
  <button>Print</button>
</div>
```
In this example:
- If focus was within the "Search" input, tab will invoke the escape behavior, moving focus to "Go".

### Scrolling interactions

Focusgroups must coexist with scrolling behavior, as arrow keys are commonly used for both focus navigation and scrolling. The priority and interaction between these behaviors depends on the context:

#### 1. Focusgroup within a scrollable region

This is the most common scenario—a focusgroup contained within a page or region that can scroll.

**For focusgroups with wrap behavior:** Focus navigation takes priority over scrolling. Arrow keys will move focus between focusgroup items, wrapping from end to start as configured. Scrolling will only occur as needed to bring the focused element into view.

**For focusgroups without wrap behavior:** Focus navigation takes priority until the focus reaches a boundary (first or last item). Once at a boundary, continuing to press arrow keys in the direction will allow normal scrolling behavior to resume.

**For focusgroups with axis restrictions:** If a focusgroup limits arrow keys to a specific axis (using `inline` or `block` tokens), then arrow keys in the cross-axis will be available for scrolling.

Example:
```html
<div style="height: 200px; overflow: auto;">
  <div focusgroup="listbox block">
    <div aria-selected="true">Item 1</div>
    <div aria-selected="false">Item 2</div>
    <div aria-selected="false">Item 3</div>
    <!-- Items 4-97 would be here, creating a long scrollable list -->
    <div aria-selected="false">Item 98</div>
    <div aria-selected="false">Item 99</div>
    <div aria-selected="false">Item 100</div>
  </div>
</div>
```

In this example:
- Up/down arrows navigate between list items in the focusgroup
- Left/right arrows scroll the container horizontally (if needed) since the focusgroup is limited to `block`
- Focus is automatically scrolled into view when navigating between items that are off-screen
- Authors should be aware that since focusgroup navigation takes priority over scrolling, they should take care when constructing large focusgroups to avoid a situation where content can be missed when jumping from one item to another.

**Accessibility considerations:** When focusgroup items are separated by large amounts of content, arrow key navigation can skip over intermediate content that users might need to read. See the [open question about scrolling behavior](#open-questions) for potential solutions being considered.

#### 2. Scrollable region within a focusgroup

When a scrollable element is contained within a focusgroup, the behavior depends on whether there's a conflict between the focusgroup's arrow key handling and the scrollable element's needs.

**No conflict scenarios:**
- Focusgroup limited to one axis, scrollable element scrolls on the cross-axis.
- Scrollable element that scrolls via different keys (Page Up/Down, etc.)

**Conflict scenarios:** When both the focusgroup and the scrollable element want to handle the same arrow keys, the scrollable element is treated as a [key conflict element](#key-conflict-elements). This means:
- Arrow keys are consumed by the scrollable element for scrolling.
- If this is a native element, and not custom script, then Tab/Shift+Tab can be used to move to adjacent focusgroup items following the [escape behavior for native key conflict elements](#escape-behavior-for-native-key-conflict-elements).

### Interaction with related web platform features

Focusgroup interacts with two web platform features related to navigation and orientation: the CSS [`reading-flow`](https://developer.mozilla.org/en-US/docs/Web/CSS/reading-flow) property and the ARIA [`aria-orientation`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-orientation) attribute.

#### Reading flow

The `reading-flow` CSS property modifies the reading order of elements for sequential navigation (Tab key) and assistive technologies. Focusgroup's directional navigation (arrow keys) respects `reading-flow`, ensuring that arrow keys move focus in the expected visual direction.

**Key points:**
- Both **sequential focus navigation** (Tab/Shift+Tab) and **directional navigation** (arrow keys) follow `reading-flow` order
- Arrow key direction is determined by visual position in the reading-flow order
- Right/Down arrows move to the next item in reading-flow order; Left/Up arrows move to the previous item
- This ensures arrow key navigation matches the visual layout established by `reading-flow`

Example:
```html
<div focusgroup="toolbar" style="display: flex; flex-direction: row-reverse; reading-flow: flex-visual;">
  <button>First in DOM</button>
  <button>Second in DOM</button>
  <button>Third in DOM</button>
</div>
```

In this example:
- Visual order (left to right): Third → Second → First
- Tab order follows reading-flow: Third → Second → First
- Arrow key navigation follows the same order: Right arrow moves from Third → Second → First
- Pressing Right Arrow moves focus visually to the right, matching user expectations

#### ARIA orientation

The `aria-orientation` attribute indicates whether a widget's orientation is horizontal, vertical, or undefined. Focusgroup does not automatically infer or set `aria-orientation` from `inline`/`block` tokens.

**Key points:**
- Focusgroup's `inline`/`block` tokens control **keyboard behavior** (which arrow keys work)
- `aria-orientation` conveys **semantic structure** to assistive technologies
- These are related but distinct concerns: axis restrictions may be used to avoid key conflicts rather than to indicate orientation
- When focusgroup applies a [minimum role](#supported-behaviors), that role's default `aria-orientation` applies unless explicitly overridden
- Authors should set `aria-orientation` explicitly when the default doesn't match the widget's semantic structure

### Restricted elements

Because `focusgroup` definitions are intended for grouping related controls, it does not make sense
to provide `focusgroup` functionality on all elements. While the `focusgroup` attribute may be defined
as a global attribute, its applicability is limited to a subset of behaviors, requiring the author to
specify the behavior their control follows when using focusgroup, see: [supported behaviors](#supported-behaviors)

The current proposal is to limit `focusgroup` to only the elements whose name match the DOM's
[valid shadow host names](https://dom.spec.whatwg.org/#valid-shadow-host-name) (which are the
elements allowed to call `attachShadow()`). However, `<table>` and some table parts will need to
be an exception in order to properly support grid `focusgroup`s.

### Feature detection

To enable feature detection, the DOM will include a `focusgroup` property, whose existence on
elements is useful for feature detection.

```webidl
partial interface HTMLElement {
  [CEReactions] attribute DOMString focusgroup;
};
```

### Additional features

Focusgroups have the following additional features:

- [Wrap-around semantics](#enabling-wrapping-behaviors) - what to do when attempting to move past
   the end of a `focusgroup`. The default/initial value is `no-wrap`, which means that focus is
   not moved past the ends of a `focusgroup` with the arrow keys. `wrap` and other tabular wrapping
   behaviors are available for `grid` `focusgroup`s.
- [Directional axis limits](#limiting-linear-focusgroup-directionality) - applies to linear
   `focusgroup`s only; respond to arrow keys in one axis only (either up/down or left/right when the
   arrow key pressed matches the corresponding flow of the content). By default, linear `focusgroup`s
   respond to all four arrow keys.
- [`focusgroup` candidacy opt-out](#opting-out) - prevent an element and its
  shadow-inclusive descendants from participating in an ancestor's `focusgroup`.
- [Memory opt-out](#disabling-focusgroup-memory) - prevent the `focusgroup` from remembering what the
   last focused element was when focus leaves a `focusgroup`. By default `focusgroup`s remember that
   element and will restore the focus to that element when the `focusgroup` is re-entered via
   sequential focus navigation.

These feature options are applied as space-separated token values to the `focusgroup`
attribute.

### Entry Priority Control

The `focusgroup-entry-priority` attribute can be set on individual focusgroup items to control which element receives focus when entering a focusgroup segment via sequential focus navigation (Tab/Shift+Tab). This attribute provides explicit control over the initial focus target within a focusgroup when no previous focus memory exists.

**Important:** If a focusgroup has memory enabled (the default) and a last-focused element exists within the segment being entered, that element will be restored instead of the element with `focusgroup-entry-priority`. Entry priority only applies when focus is entering the focusgroup for the first time or when using `no-memory` to disable the memory feature.

```html
<div focusgroup="toolbar">
  <button>Bold</button>
  <button focusgroup-entry-priority>Italic (recommended)</button>
  <button>Underlined</button>
</div>
```

When multiple elements within the same [focusgroup segment](#focusgroup-segments) have the `focusgroup-entry-priority` attribute, the first element with the attribute in DOM order will be prioritized, or if the items are also being managed by reading-flow, the first such item in reading order. The direction of navigation (Tab vs Shift+Tab) does not affect which element is chosen - the same element will always receive focus when entering the segment, promoting consistent user experience.

**Key behaviors:**
- Focusgroup items with `focusgroup-entry-priority` are prioritized.
- If no focusgroup item has `focusgroup-entry-priority`, the first focusgroup item in the segment is chosen (in DOM order, or if the items are also being managed by reading-flow, in reading order).
- Memory (when enabled) takes precedence over entry priority - a previously focused element will be restored even if other elements have `focusgroup-entry-priority`

#### Memory vs Entry Priority Example

This example demonstrates how memory takes precedence over entry priority:

```html
<div focusgroup="toolbar" aria-label="Text formatting">
  <button>Bold</button>
  <button focusgroup-entry-priority>Italic (entry priority)</button>
  <button>Underline</button>
</div>
```

**Behavior sequence:**
1. **First time entering the focusgroup:** Focus goes to "Italic" (entry priority applies since no memory exists)
2. **User arrows to "Underline":** Focus moves to "Underline" and memory is updated
3. **User tabs away and then back:** Focus goes to "Underline" (memory restored, entry priority ignored)
4. **Using `no-memory`:** With `focusgroup="toolbar no-memory"`, focus would always go to "Italic" regardless of previous focus

#### Multiple Items with the Entry Priority Attribute (Not Recommended)
Focusgroup will always prioritize the first element with the `focusgroup-entry-priority` attribute in DOM order when entering a focusgroup segment, or if the items are also being managed by reading-flow, the first such item in reading order, and will not consider any subsequent elements with the same attribute.

```html
<div focusgroup="toolbar no-memory">
  <button>Bold</button>
  <button focusgroup-entry-priority>Italic</button>
  <button focusgroup-entry-priority>Underline</button>
  <button>Strikethrough</button>
</div>
```
In this example, "Italic" will receive focus when entering the focusgroup because it appears first in DOM order among elements with `focusgroup-entry-priority`, or if the items are also being managed by reading-flow, it would be the first in reading order among elements with `focusgroup-entry-priority`.

#### Interaction with Nested Focusgroups

When focusgroups are nested, each focusgroup manages its own entry priority independently. The `focusgroup-entry-priority` attribute only affects the focusgroup that directly contains the element.

```html
<div focusgroup="toolbar" aria-label="Main toolbar">
  <button>Save</button>
  <button focusgroup-entry-priority>Print</button>

  <!-- Nested focusgroup with its own entry priority -->
  <div focusgroup="toolbar" aria-label="Text formatting">
    <button>Bold</button>
    <button focusgroup-entry-priority>Italic</button>
    <button>Underline</button>
  </div>

  <button>Close</button>
  <button focusgroup-entry-priority>Exit</button>
</div>
<button>After</button>
```

In this example, there are two distinct focusgroups, and three focusgroup segments:

**Main toolbar**: `[Save, Print]`, `[Close, Exit]`
- Entry priority: "Print" (has `focusgroup-entry-priority`)

**Nested toolbar**: `[Bold, Italic, Underline]`
- Entry priority: "Italic" (has `focusgroup-entry-priority`)

**Sequential navigation behavior:**
1. **Tab into main toolbar:** Focus goes to "Print" (entry priority)
2. **Tab from "Print":** Focus moves to "Italic" (entry priority in nested toolbar)
3. **Tab from nested toolbar:** Focus moves to "Close" (continuing in main toolbar)
4. **Shift+Tab into main toolbar from "After":** Focus goes to "Exit" (entry priority)

**Directional navigation behavior:**
- Arrow key navigation within the main toolbar moves between "Save", "Print", "Close", and "Exit", but skips over the nested toolbar
- Arrow key navigation within the nested toolbar moves between "Bold", "Italic", and "Underline"
- Each focusgroup maintains independent arrow navigation

This demonstrates how entry priority works independently for each nested focusgroup and how exiting and entering nested focusgroups respects each segment's entry priority.

#### Interaction with Opted-Out Subtrees

When elements opt out of a focusgroup using `focusgroup="none"`, they can create multiple [focusgroup segments](#focusgroup-segments), each with their own entry priority behavior.

```html
<div focusgroup="toolbar no-memory" aria-label="Document toolbar">
  <button>New</button>
  <button focusgroup-entry-priority>Open</button>
  <button>Save</button>

  <!-- Opted-out help section -->
  <div focusgroup="none" aria-label="Help section">
    <button>Help</button>
    <button>Shortcuts</button>
  </div>

  <button>Close</button>
  <button focusgroup-entry-priority>Exit</button>
</div>
```

In this example, the opted-out help section creates two focusgroup segments:

**Segment 1** (before the opted-out section): `[New, Open, Save]`
- Entry priority: "Open" (has `focusgroup-entry-priority`)

**Segment 2** (after the opted-out section): `[Close, Exit]`
- Entry priority: "Exit" (has `focusgroup-entry-priority`)

**Sequential navigation behavior:**
1. **Tab into Segment 1:** Focus goes to "Open"
2. **Tab from "Save":** Focus moves to "Help" (first opted-out element)
3. **Tab from "Shortcuts":** Focus moves to "Exit" (entry priority in Segment 2)
4. **Shift+Tab from "Help":** Focus returns to Segment 1, going to "Open" (entry priority)

** Directional navigation behavior:**
- Arrow key navigation can move freely across both segments, skipping over the opted-out help section.

This demonstrates how entry priority works independently within each segment created by opted-out elements.


## Enabling wrapping behaviors

By default, `focusgroup` traversal with arrow keys ends at boundaries of the `focusgroup` (the start and
end of a linear `focusgroup`, and the start and end of both rows and columns in a grid `focusgroup`).
The following `focusgroup` definition values change this behavior:

| HTML (attribute value) | Applies To | Effect |
|---|---|---|
| `focusgroup="<behavior>"` (where `<behavior>` is one of the non-grid behaviors) | linear | No wrapping; edges are hard stops. |
| `focusgroup="<behavior> wrap"` (where `<behavior>` is one of the non-grid behaviors) | linear | Moving past one end wraps focus to the opposite end. |
| (default) `focusgroup="grid"` | grid | No wrapping; row and column edges are hard stops. |
| `focusgroup="grid wrap"` | grid | Rows and columns wrap within their own row/column (end → start of same row/column). |
| `focusgroup="grid row-wrap"` | grid | Rows wrap; columns do not. |
| `focusgroup="grid col-wrap"` | grid | Columns wrap; rows do not. |
| `focusgroup="grid flow"` | grid | Moving past row end jumps to start of NEXT row (and reverse); same for columns. Last row/column flows to first. |
| `focusgroup="grid row-flow"` | grid | Rows flow; columns are hard stops. |
| `focusgroup="grid col-flow"` | grid | Columns flow; rows are hard stops. |
| `focusgroup="grid row-wrap col-flow"` | grid | Rows wrap; columns flow. |
| `focusgroup="grid row-flow col-wrap"` | grid | Rows flow; columns wrap. |

Specifying both `row-wrap` and `row-flow` in one HTML `focusgroup` definition is an author error. Only
one declaration for row behavior is allowed. Similarly for `col-wrap` and `col-flow`.

## Limiting linear focusgroup directionality

In many cases, having multi-axis directional movement (e.g., both right arrow and down arrow linked
to the forward direction) is not desirable, such as when implementing a
[tablist control pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/), in which case it may not
make sense for the up and down arrows to also move the focus left and right. Likewise, when moving
up and down in a vertical menu, the author might wish to use JavaScript to provide other behavior
for the left and right arrow keys such as opening or closing sub-menus. In these situations, authors
can limit the linear `focusgroup` to one-axis traversal.

Note that the following only apply to linear `focusgroup` definitions. (All currently supported behaviors are linear; grid is a future consideration.)

_Note: `<behavior>` below refers to one of the non-grid behaviors._
| HTML (attribute value) | Explanation |
|---|---|
| (default) `focusgroup="<behavior>"` | Items respond to forward/backward movement via both inline and block arrow keys (where they map to forward/back). |
| `focusgroup="<behavior> inline"` | Items respond only to arrow keys parallel to the inline axis (e.g., Left/Right in `horizontal-tb`). |
| `focusgroup="<behavior> block"` | Items respond only to arrow keys parallel to the block axis (e.g., Up/Down in vertical menus or vertical writing modes). |

Example:

```html
<tab-group focusgroup="tablist inline wrap">
  <a-tab role="tab" aria-selected="true" aria-controls="…">…</a-tab>
  <a-tab role="tab" aria-selected="false" aria-controls="…">…</a-tab>
  <a-tab role="tab" aria-selected="false" aria-controls="…">…</a-tab>
</tab-group>
```

In the above example, when the focus is on the first `<a-tab>` element, pressing either the up or
down arrow key does nothing because the `focusgroup` is configured to only respond to the inline
(left/right in this case) arrow keys.

Because 2-axis directionality is the default, specifying both `inline` and `block` at the
same time on one `focusgroup` is not allowed:

Example:

```html
<!-- This is an example of what NOT TO DO -->
<radiobutton-group focusgroup="inline block wrap" role="radiogroup">
  ⚠️This `focusgroup` configuration is an error--neither constraint will be applied (which is actually
  what the author intended).
</radiobutton-group>
```

## Opting-out

`focusgroup` definitions assigned to an element create `focusgroup` candidates that include
the element itself and all its _shadow-inclusive descendant elements_. Any element within that
`focusgroup` scope that is (or becomes) focusable will automatically become a `focusgroup` item
belonging to its ancestor's `focusgroup`.

With such an expansive opt-in behavior, it is important to provide an opt-out for elements or
element subtrees. For example: focusable elements that wish to remain in sequential focus
navigation and have arrow key navigation pass them over; or, components nested across a
Shadow DOM boundary that wish to be excluded from `focusgroup` participation.

Opting-out applies to the element making the declaration as well as its shadow-inclusive
descendants.

To opt-out:

| HTML (attribute value) | Explanation |
|---|---|
| `focusgroup="none"` | Opt-out: this element and its shadow-inclusive descendants are not considered `focusgroup` candidates. |

### Impact on sequential focus navigation

When elements opt-out of a `focusgroup` using `focusgroup="none"`, they can effectively divide the focusgroup for sequential focus navigation purposes, creating multiple tab stops where the focusgroup would normally have only one. This happens because opted-out elements remain in the normal sequential focus navigation order, necessitating the splitting the focusgroup into separate segments to ensure content is not skipped.

Sequential focus navigation within each resulting segment follows the visual reading order established by CSS [`reading-flow`](#reading-flow) when applied to the container or relevant ancestors.

In the following example, a help section opts-out of `focusgroup` behavior so that any interactive content inside it is bypassed when arrowing among the primary formatting controls, but remains reachable via tabbing.

```html
<div focusgroup="toolbar inline wrap" aria-label="Text formatting">
  <button type="button">Bold</button>
  <button type="button">Italic</button>
  <span focusgroup="none" aria-label="Help group">
    <button type="button">Help</button>
    <button type="button">Shortcuts</button>
  </span>
  <button type="button">Underline</button>
</div>
```

**Sequential focus navigation behavior:**

When a user navigates into a focusgroup using Tab or Shift+Tab, the user agent determines the appropriate focusgroup segment and applies the [guaranteed tab stop algorithm](#guaranteed-tab-stop-algorithm):

1. **Entering from before:** Pressing Tab to enter this focusgroup from a preceding element will focus "Bold". The focusgroup segment includes only the items reachable without crossing opted-out elements ("Bold" and "Italic").

2. **Tab from "Bold":** Pressing Tab moves focus to "Help" (the first opted-out element in sequential order).

3. **Tab from "Help":** Pressing Tab moves focus to "Shortcuts" (following normal sequential focus navigation within the opted-out subtree).

4. **Tab from "Shortcuts":** Pressing Tab will **re-enter the focusgroup**. The focusgroup segment now includes only items that follow "Shortcuts" without crossing opted-out elements ("Underline"). Since "Underline" is the only focusgroup item in the segment, the guaranteed tab stop algorithm focuses "Underline".

5. **Shift+Tab from "Help":** Pressing Shift+Tab will move focus back to the focusgroup segment that precedes "Help" in tree order ("Bold" and "Italic"). The guaranteed tab stop algorithm is applied only to this segment, considering any memory and sequentially focusable items within this segment only.

**Key behaviors:**

- **Focusgroup segments:** As defined above, opted-out elements create boundaries that divide the focusgroup.
- **Guaranteed tab stop per segment:** Each segment follows the [guaranteed tab stop algorithm](#guaranteed-tab-stop-algorithm).
- **Memory scope:** Focusgroup memory restoration only applies if the memory item is in the segment being entered.
- **Direction-based segment selection:** Tab vs Shift+Tab determines which segment is considered for entry.

**Arrow key navigation is unaffected:** Arrow keys skip over opted-out elements entirely, treating them as if they don't exist for arrow navigation purposes.

### Nested Focusgroups

When a `focusgroup` definition is applied to an element, it implicitly opts out of any ancestor's
`focusgroup`s. This ensures that every element can only belong in one `focusgroup` at a time.

Example:

```html
<ul focusgroup="menubar" aria-label="Site">
  <li role="none">
    <ul focusgroup="menu" aria-label="Products">
      <li><button role="menuitem">Item A</button></li>
      <li>
        <ul focusgroup="menu" aria-label="More">
          <li><button role="menuitem">Sub A1</button></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
```

- The outer menubar `ul[role="menubar"][focusgroup]` defines one `focusgroup` (its direct menuitems would participate when present).
- The first nested `ul[role="menu"][focusgroup]` creates an independent `focusgroup` and is implicitly not part of the menubar's arrow navigation.
- The innermost `ul[role="menu"][focusgroup]` (submenu) defines yet another independent `focusgroup`, likewise not part of its ancestor menu's `focusgroup`; its `menuitem` participates only in that deepest scope.

## Disabling focusgroup memory

By default, when a linear or grid `focusgroup` is defined it includes a "memory" of the
last-focused element within its scope, initially empty. Each time the focus is changed
within a `focusgroup`, the "memory" is updated to refer to that element. This behavior is
akin to the
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
in which the "memory" is the stateful `tabindex="0"` value assigned to the currently
focused element.

In some scenarios it is not desirable to have a `focusgroup` maintain a memory. Usually this
is because there is a more relevant element which should take focus when entering the `focusgroup`
instead of the most-recently-focused element. For example, an active (selected) tab in a
`role="tablist"` container, rather than the last-focused tab (when selection does not follow focus).

To disable the `focusgroup`'s default memory, use the value `no-memory`:

_Note: `<behavior>` below refers to any valid focusgroup behavior._
| HTML (attribute value) | Explanation |
|---|---|
| (default) `focusgroup="<behavior>"` | `focusgroup` remembers the last-focused element and redirects focus to it when entered via sequential focus navigation. |
| `focusgroup="<behavior> no-memory"` | `focusgroup` will not remember the last-focused element. |

After the `focusgroup`'s memory has been set, it must be cleared whenever any one of the following
change:

* The element with the `focusgroup` definition is `hidden` or un-hidden; or if the currently remembered
  element is `hidden` or un-hidden.
* The element with the `focusgroup` definition has its `disabled` or `inert` status changed; or if the
  currently remembered element has its `disabled` or `inert` status changed.
* The element with the `focusgroup` definition is removed from the shadow-inclusive tree; or if the
  currently remembered element is removed from the shadow-inclusive tree.
* The currently remembered element stops being focusable (e.g., a `<div>` with a `tabindex` has its
  `tabindex` attribute removed).
* The currently remembered element is changed to become excluded from the `focusgroup` (through
  `focusgroup="none" on itself or a shadow-inclusive ancestor, or by changing `focusgroup`s: if a new
   `focusgroup` definition appears on itself or one of its shadow-inclusive ancestor elements).

## Adjustments to sequential focus navigation

To ensure that a [focusgroup segment](#focusgroup-segments) has exactly one tab stop in the sequential focus navigation
order, and to provide the appropriate "hook" for a `focusgroup`'s "memory" to redirect focus to the
last-focused element in a `focusgroup`, a change to sequential focus navigation is needed.

### Guaranteed tab stop algorithm

When a user navigates into a focusgroup using Tab or Shift+Tab, the user agent must:

#### 1. **Identify the focusgroup segment:** The set of `focusgroup` items that are reachable without crossing any [opted-out items](#opting-out) in tree order from the entry point.

#### 2. **Apply focus priority (first match wins):**
  - If the focusgroup has a **last focused item** and the [`no-memory`](#disabling-focusgroup-memory) token is not present, and the last focused item is within the current segment, focus that item.
   - Otherwise, if an item within the segment has the `focusgroup-entry-priority` attribute, focus the first such item in tree order, or if the items are also being managed by reading-flow, focus the first such item in reading order.
   - Otherwise, if an item within the segment is **sequentially focusable** (e.g., has `tabindex="0"` or is a natively focusable element like `<button>`), focus the first such item in tree order, or if the items are also being managed by reading-flow, focus the first such item in reading order.


#### 3. **Update tab navigation:**
All other `focusgroup` items are not considered in sequential focus navigation order. Memory is updated to be on the newly focused item if the [`no-memory`](#disabling-focusgroup-memory) token is not present.
____
This algorithm ensures that each [focusgroup segment](#focusgroup-segments) has a single [guaranteed tab stop](#guaranteed-tab-stop), without the need for authors to manage `tabindex` values. Authors can use the `focusgroup-entry-priority` attribute to explicitly specify which element should receive focus when entering a focusgroup segment.

Additionally, when focus is within [native key conflict elements](#key-conflict-elements), immediate
neighboring focusgroup items are automatically made available in the tab order to provide an
[escape mechanism](#escape-behavior-for-native-key-conflict-elements).

## (Future Consideration) Grid focusgroups
<details>
Some focusable data is structured not as a series of nested linear groups, but as a
2-dimensional grid such as in a spreadsheet app, where focus can move logically from
cell-to-cell either horizontally or vertically. In these data structures, it makes
sense to support the user's logical usage of the arrow keys to move around the data.

Grid navigation is expected to happen within well-structured content with consistent
rows and columns where DOM structure reflects this organization. In `focusgroup` grid
navigation, only the cells in the grid are `focusgroup` candidates and only the focusable
cells become `focusgroup` items. It is not currently possible to use grid `focusgroup`s to
support other focusable tabular parts such as focusable row elements (see
[comment in issue 1018](https://github.com/openui/open-ui/issues/1018#issuecomment-2013053227) for
a possible future addition for this use case).

### Applicability to tabular data

The arrow navigation in the grid (and in the previous non-grid scenarios) should
reflect the accessible structure of the document, not the presentation view made
possible with CSS. For example, it is easy to create views that visually appear
grid-like, but do not make sense to navigate like a grid if considering that the
data model is fundamentally a list, which is how users of accessibility technology
would perceive it. Wrapping a list of contact cards on screen in a grid-like
presentation allows for more content density on screen for sighted users. In that
scenario, arrow key navigation to move linearly (left-to-right following the
line-breaking across each line) through the contents makes sense (especially if
these are alphabetized), but orthogonal movement through the "grid" (up/down when
cards are aligned or in a masonry layout) jumps the focus to seemingly arbitrary
locations. Multi-directional arrow key navigation may seem appropriate for sighted
users that have the visual context only, but are not appropriate for assistive
technology. In the case of the list-presented-as-a-grid scenario, a linear
focusgroup will make the most sense for sighted as well as users with accessibility
needs.

When considering using a grid `focusgroup`, be sure that the data is structured
like a grid and that the structure makes semantic sense in two dimensions (and not
just for a particular layout or presentation).

Tabular data can be structured using column-major or row-major organization. Given
that HTML tables and ARIA attributes for grids (`role="grid"`, `role="row"`, `role="gridcell"`)
only exist for row-major grid types, this proposal does **not define** grid `focusgroup`
organization for column-major data structures (and assumes row-major data structures
throughout).


### Setting up a grid focusgroup

Grid `focusgroup`s can be created "automatically" or manually. Automatic grids use the context
of existing HTML semantics for tables as the structural components necessary to provide grid-based
navigation. Any elements with computed table layout are suitable for an automatic grid (e.g.,
`display: table-row` in place of using a `<tr>` elements).
[Manual grid](#manual-grids-row-and-cell-connections) creation requires
annotating specific elements with their `focusgroup` grid component names.

Note: We are evaluating the suitability for CSS `display: grid` to create automatic grids.

The automatic grid approach will be preferable when the grid contents are uniform
and consistent and when re-using semantic elements for grids (typical). The manual
approach may be necessary when the grid structure is not uniform or structurally
inconsistent (atypical), and involves identifying the parts of the grid on specific
`focusgroup` candidates using CSS.

Elements with the `grid` `focusgroup` definition on the root element of the structural
grid become automatic grid `focusgroup`s. The implementation must attempt to validate
the structure of the grid to ensure it has appropriate row and cell structures. In the
event that the implementation cannot automatically determine the grid structure, then
the definition is ignored (i.e., there is no fallback to a linear grid).

| HTML | Explanation |
|---|---|
| `focusgroup="grid"` | Establishes the root of an automatic grid `focusgroup`. Shadow-inclusive descendants of the automatic grid are identified and assigned `focus-group-type: grid-row` and `focus-group-type: grid-cell` `focusgroup` candidate status automatically. |

Example:

```html
<table aria-label="Tic tac toe grid" role="grid" focusgroup="grid">
  <tr>
    <td tabindex="0"></td>
    <td tabindex="0"></td>
    <td tabindex="0"></td>
  </tr>
  <tr>
    <td tabindex="0"></td>
    <td tabindex="0"></td>
    <td tabindex="0"></td>
  </tr>
  <tr>
    <td tabindex="0"></td>
    <td tabindex="0"></td>
    <td tabindex="0"></td>
  </tr>
</table>
```

The `<table>`'s grid `focusgroup` definition automatically establishes each of its
descendant `<tr>`s as `focusgroup` rows (the parser-generated `<tbody>` is
accounted for) and `<td>`s as `focusgroup` cells. All cells have `tabindex="0"` to make them focusable and thus eligible to be `focusgroup` items. The focusgroup manages which cell is actually reachable via sequential navigation while allowing arrow key navigation between all cells. Among all `focusgroup` cells, the left/right arrow keys navigate between cells
in the table, and up/down arrow keys will compute the new target based on the DOM position of the
current `focusgroup` candidate cell in relation to the `focusgroup` candidate row.

### Manual grids: row and cell connections

A manual grid is declared in a `focusgroup` definition with the name `manual-grid`.
With a manual grid, the rows and cells must be explicitly indicated using `grid-row` and
`grid-cell`:

| HTML (attribute value) | Explanation |
|---|---|
| `focusgroup="manual-grid"` | Establishes the root of a manual grid `focusgroup`. Shadow-inclusive descendants must be identified explicitly as grid rows and grid cells. |
| `focusgroup="grid-row"` | Must be a shadow-inclusive descendant of a manual grid `focusgroup` root. |
| `focusgroup="grid-cell"` | Must be a shadow-inclusive descendant of a manual grid `focusgroup` root and also a shadow-inclusive descendant of a grid row. |

Cells cannot be descendants of other cells, and rows cannot be descendants of other rows.

Each `focusgroup` candidate will perform an ancestor search to locate its nearest grid structural
component: cells will look for their nearest row, and rows will look for their nearest grid root.

In the following example, the `<my-cell>`s are all meant to be on the same row of the
grid, and the rows are designated by `<my-row>` elements:

Example:

```html
<my-root role="grid" focusgroup="manual-grid">
  <div role="none" class="presentational_wrapper">…</div>
  <my-row role="row" focusgroup="grid-row">
    <first-thing role="gridcell" focusgroup="grid-cell">…</first-thing>
    <cell-container role="none">
      <my-cell role="gridcell" focusgroup="grid-cell">…</my-cell>
      <my-cell role="gridcell" focusgroup="grid-cell">…</my-cell>
    </cell-container>
    <cell-container role="none">
      <my-cell role="gridcell" focusgroup="grid-cell">…</my-cell>
      <my-cell role="gridcell" focusgroup="grid-cell">…</my-cell>
    </cell-container>
  </my-row>
  <!-- repeat pattern of div/my-row pairs... -->
</my-root>
```

The following non-uniform structure can still have grid semantics added
via `manual-grid`:

Example:

```html
<div role="grid" focusgroup="manual-grid flow">
  <div role="row" focusgroup="grid-row">
    <div>
      <div role="gridcell" focusgroup="grid-cell"></div>
      <div role="gridcell" focusgroup="grid-cell"></div>
    </div>
  </div>
  <div>
    <div role="row" focusgroup="grid-row">
      <div role="gridcell" focusgroup="grid-cell"></div>
      <div role="gridcell" focusgroup="grid-cell"></div>
    </div>
  </div>
  <div>
    <div>
      <div role="row" focusgroup="grid-row">
        <div>
          <div role="gridcell" focusgroup="grid-cell"></div>
          <div role="gridcell" focusgroup="grid-cell"></div>
        </div>
      </div>
    </div>
  </div>
</div>
```

### Grid focusgroup nesting

Unlike linear `focusgroup`s, an automatic or manual grid `focusgroup` requires a small degree of DOM
structure to work correctly. Unless the proper structure exists, the grid `focusgroup` won't work.

Attempts to define new grid or linear `focusgroup`s among the DOM elements that make up the
structure of a grid `focusgroup` (such as on or between elements defining the root grid
container, the grid-rows and the grid-cells) will be ignored. However new grid or linear
`focusgroup`s **can be defined** on elements that are shadow-inclusive descendants of grid-cell
elements (e.g., that are outside the set of elements making up the grid's DOM structure).

### Empty Cell data

Like linear `focusgroup`s, focus is only set on elements that are focusable. The arrow key navigation
algorithms look for the first `focusgroup` item (in DOM order) of a grid `focusgroup` cell in the
direction the arrow was pressed. Non-focusable grid `focusgroup` candidates of a `focusgroup` cell
are passed over in the search.

### Non-uniform cells

It is entirely possible to have rows with non-uniform numbers of cells. In these
cases, `focusgroup` navigation behaviors may not work as visibly desired. Algorithms
for navigating grid `focusgroup`s will work based on content the grid content structure
as specified. If the algorithms conclude that there is no "next candidate cell" to
move to (e.g., in a grid with two rows, and the bottom row has three cells, and the
top row only two, if the focus is on the 3rd cell, a request to move "up" to the prior
row cannot be honored because there is no "3rd cell" in that row.

</details>

## (Future Consideration) Additional Keyboard support

In addition to arrow keys, the `focusgroup` should also enable other navigation keys such as
pageup/down for paginated movement (TBD on how this could be calculated and in what
increments), as well as the home/end keys to jump to the beginning and end of groups.

It might also be interesting to add support for typeahead scenarios (though what values to
look for when building an index would need to be worked out, and may ultimately prove to be
too complicated).


### Authoring guidance
1. Put the behavior token first: `focusgroup="tablist wrap"`, `focusgroup="toolbar"`.
2. Omit common child roles unless you need a variant (checkbox / radio menu items, mixed controls, etc.).
3. For detailed precedence (mismatches, inference limits, overrides) see [Behavior → role mapping & precedence](#behavior--role-mapping--precedence).

## Alternatives considered
When considering how to ensure that `focusgroup` usage is scoped to scenarios we want, the following
approaches were considered.
1. Role-required gating (original): only activates when an eligible `role` attribute is present. Rejected: couples behavior activation to ARIA; breaks precedent.
2. Parent-only implicit role (earlier alternative): ensures that aria norms are followed, while still allowing authors to avoid repetition.
3. Adopted (parent token + child inference): Same as above, but additionally sets the expected role on children that participate in the `focusgroup`.
## Open Questions

1. **Supported Behaviors:** The [list of supported behaviors for `focusgroup`](#supported-behaviors) is open for discussion, and I am open to input on what should be allowed.
  * MDN documentation includes [a recommendation to **not**](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles) use `grid` and `listbox` as composite widgets, but supporting them here would send a signal that it is OK to use them in this scenario.
  * Are there other roles not listed here that have a strong use case for `focusgroup`?
2. **Grid Support:** The functionality for `grid` and other 2-D navigation has been moved to "Future Considerations" due to its complexity. I am open to discussing how to best implement this functionality in the future including if this should be moved into a separate explainer.
3. **CSS Mappings:** This explainer does not currently define specific CSS mappings for `focusgroup`, but this is an area that could be explored in the future, or if others feel this is integral to the feature, this could be considered to be added back in.
4. **Attribute Functionality and Dependencies:** Feedback requested on adopted scoping (role token + optional child role inference):
  - Exact list & phased expansion of child role inference set (which roles, staged rollout?).
  - Should mismatched explicit container `role` vs first token trigger a console warning or be silent?
  - Policy for console warnings vs silent ignore on token / role mismatches.
5. **Alternative approaches to scope focusgroup to specific scenarios**
  - (A) Current: first token = pattern + (optional) child role inference.
  - (B) Require explicit container `role`; tokens only modifiers (drops role token entirely).
  - (C) Split into two attrs: `pattern="tablist" focusgroup="wrap"` (clearer separation, extra verbosity & API surface).
  - (D) Native elements only (e.g., future `<tabs>`, `<toolbar>`, `<menubar>`); attribute becomes redundant—risk: slower coverage, custom element ecosystems still need declarative navigation.
  - Criteria to decide: author error rate, implementation complexity, consistency with existing HTML token patterns, incremental ship path.
6. **Scrolling behavior when focus target is not in view:** Should focusgroup navigation automatically prioritize scrolling over focus movement when the next focusable item is not currently visible? This addresses accessibility concerns where arrow key navigation can skip over intermediate content that users need to read (see [GitHub issue #1008](https://github.com/openui/open-ui/issues/1008)). Potential solution:
  - Temporarily disable focusgroup navigation when the target item is out of view, allowing normal scrolling until the item becomes visible.
7. **Keep or drop child role inference (or defer as future consideration):** Should v1 exclude automatic child role assignment entirely to reduce complexity
      and perceived overreach (keeping only container pattern + navigation)? Rationale for revisiting: reviewer concern about mixing semantics & behavior;
      authors can still supply explicit roles; deferring would let us ship navigation sooner and gather data on real author pain before standardizing inference.

## Privacy and Security Considerations

### Privacy

No considerable privacy concerns are expected, but we welcome community feedback.

### Security

No significant security concerns are expected.

## Design decisions

Here is a short list to issue discussions that led to the current design of focusgroup.

* [focusgroup works across Shadow DOM boundaries by default](https://github.com/openui/open-ui/issues/521)
* [arrow key movement and directionality constraints should be aligned with content direction (add inline/block)](https://github.com/openui/open-ui/issues/522)
* [focusgroup definitions should not be limited to direct-children](https://github.com/openui/open-ui/issues/989)
* [focusgroup should include a memory](https://github.com/openui/open-ui/issues/537)
* [focusgroup should be restricted to some elements only](https://github.com/openui/open-ui/issues/995)
* [Default behaviour for key conflict elements](https://github.com/openui/open-ui/issues/1281)
* [Scrolling interactions with focusgroup](https://github.com/whatwg/html/issues/11641)

See other [open `focusgroup` issues on GitHub](https://github.com/openui/open-ui/issues?q=is%3Aissue+is%3Aopen+label%3Afocusgroup).

## Index of focusgroup values

Tokens are space-separated. Order: first token MUST be a supported behavior token (eligible list below). Remaining tokens are modifiers. Unknown tokens are ignored.

Behavior tokens: See the earlier Supported Behaviors mapping table for the definitive list, minimum container roles, and child inference notes. Explicit container and child roles always override any inference.

***Focusgroup directions:***

| Description | HTML syntax |
|---|---|
| both directions for a linear `focusgroup` | (unspecified value; default value) |
| inline direction for a linear `focusgroup` | `inline` |
| block direction for a linear `focusgroup` | `block` |

***Focusgroup wrapping:***

| Description | HTML syntax |
|---|---|
| no wrap | (unspecified value; default value) |
| wrap | `wrap` |
| flow (grid focusgroups only) | `flow` |
| column specific | `col-wrap`, `col-flow`, `col-none` |
| row specific | `row-wrap`, `row-flow`, `row-none` |

***Focusgroup memory:***

| Description | HTML syntax |
|---|---|
| enable memory | (unspecified value; default value) |
| disable memory | `no-memory` |

Authoring shorthand examples:

| Pattern | Markup |
|---|---|
| Wrapping toolbar | `<div focusgroup="toolbar wrap">…` |
| Horizontal manual-activation tabs (no memory) | `<div focusgroup="tablist inline wrap no-memory">…` |
| Simple radiogroup | `<div focusgroup="radiogroup">…` |
| Vertical listbox (block axis) | `<div focusgroup="listbox block">…` |

## Acknowledgments

Thanks to everyone who spent time discussing and contributing to the focusgroup design and implementation, including the members of the OpenUI Community Group. Your insights, ideas, and contributions have been indispensable.
